package epoch.game.core.netty;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

import epoch.game.core.buffer.IBuffer;
import epoch.game.core.server.ISession;
import io.netty.channel.Channel;

public class NettySession implements ISession {
	//默认申请的buff长度
		private final static int DEFAULT_SEND_BUFFER_SIZE=64*1024;
	private Channel channel;
	private long id;
	private AtomicLong idGen = new AtomicLong();
	private String remoteIp;
	private Map<String, Object> attr;
	// 缓存消息
	private LinkedBlockingQueue<byte[]> bufferQueue = new LinkedBlockingQueue<>();
	// 会话状态
	private volatile int state;
	// 正在关闭中
	private volatile boolean closing = false;

	public NettySession() {
		id = idGen.addAndGet(1);
	}

	public NettySession(Channel channel) {
		this.channel = channel;
		id = idGen.addAndGet(1);
	}

	@Override
	public long getId() {
		return id;
	}

	@Override
	public void write(byte[] bytes) {
		channel.write(bytes);
	}

	@Override
	public void write(Object message) {
		channel.write(message);
	}

	@Override
	public SocketAddress remoteAddress() {
		return channel.remoteAddress();
	}

	@Override
	public String remoteIP() {
		if (remoteIp == null) {
			SocketAddress addr = channel.remoteAddress();
			if (addr != null) {
				InetSocketAddress sockAddr = (InetSocketAddress) addr;
				if (sockAddr.getAddress() != null) {
					remoteIp = sockAddr.getAddress().getHostAddress();
				}
			}
		}
		return remoteIp;
	}

	@Override
	public void setAttribute(String key, Object obj) {
		if (attr == null) {
			attr = new HashMap<>();
		}
		attr.put(key, obj);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T getAttribute(String key) {
		if (attr != null) {
			return (T) attr.get(key);
		}
		return null;
	}

	@Override
	public boolean containsAttribute(String key) {
		if (attr == null) {
			return false;
		}
		return attr.containsKey(key);
	}

	@Override
	public void removeAttribute(String key) {
		if (attr == null) {
			return;
		}
		attr.remove(key);
	}

	@Override
	public void close() {
		channel.close();
	}

	@Override
	public void close(boolean force) {
		if (force) {
			channel.close();
		} else {
			closing = true;
			channel.closeFuture();
		}
	}

	@Override
	public void close(boolean force, long delay) {
		closing = true;
		if (delay > 0) {
			new Timer().schedule(new TimerTask() {

				@Override
				public void run() {
					close(force);
				}

			}, delay);
		} else {
			close(force);
		}
	}

	@Override
	public boolean isConnected() {
		return channel.isActive();
	}

	@Override
	public void writeToSendBuffer(byte[] msg, boolean needCopy) {
		if(closing){//discard...
			return;
		}
		if(msg.length==0){
			return;
		}
		byte[] bytes;
		if (needCopy) {
			bytes = new byte[msg.length];
			System.arraycopy(msg, 0, bytes, 0, msg.length);
		} else {
			bytes = msg;
		}
		bufferQueue.add(bytes);
	}

	@Override
	public int flushSendBuffer() {
		byte[] msg = bufferQueue.poll();
		if (msg != null) {
			IBuffer buffer = IBuffer.alloc(DEFAULT_SEND_BUFFER_SIZE);
			buffer.writeBytes(msg);
			for (;;) {
				msg = bufferQueue.poll();
				if (msg == null) {
					break;
				}
				buffer.writeBytes(msg);
			}
            int size = buffer.readableBytes();
			channel.write(buffer);
            return size;
		}
		return 0;
	}
	
	@Override
	public long getScheduledWriteBytes() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long getSendBufferSize() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int getState() {
		return state;
	}

	@Override
	public void setState(int state) {
		this.state = state;
	}

	@Override
	public boolean isClosing() {
		return closing;
	}

}
